package mllib;

import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.ArrayRealVector;
import org.apache.commons.math.linear.RealMatrix;
import org.apache.commons.math.linear.RealVector;
import org.apache.commons.math.stat.StatUtils;

public class TrainingSet 
{    
    private RealMatrix data;
    private int dim;
    private int samples;


    //Builds a TrainingSet object from the data in 'm'. Transposes the data if 
    //necessary.
    public TrainingSet(double[][] m, boolean transpose) {
        if(transpose)
          data = new Array2DRowRealMatrix(m).transpose();
        else
          data = new Array2DRowRealMatrix(m);

        dim = data.getRowDimension();
        samples = data.getColumnDimension();
    }

    
    //Some necessary accessors
    public int dimension()
    {
        return dim;
    }

    public int sampleSize()
    {
        return samples;
    }

    public RealVector getSample( int i) 
    {
        return data.getColumnVector(i);
    }
    

    //Returns a vector of the mean value in each direction
    public RealVector mean()
    {
            ArrayRealVector mu = new ArrayRealVector( dim );        
            for( int row = 0; row < dim; row++)
                mu.setEntry( row, StatUtils.mean( data.getRow(row) ) );        
            return mu;
    }


    //Shifts each datapoint by vector v so that data is centered about origin.
    //Returns v.
    public RealVector centerToOrigin()
    {
        RealVector mu = mean();
        for( int i = 0; i < dim; i++)
            for( int j = 0; j < samples; j++)
                data.addToEntry( i, j, -mu.getEntry(i));
        return mu;
    }

    public RealVector variance()
    {
        RealVector m = mean();
        double[] v = new double[dim];
        for( int i = 0; i < dim; i++)
        {
            double sum = 0;
            for( int j = 0; j < samples; j++)
                sum += (data.getEntry(i,j) - m.getEntry(i)) * (data.getEntry(i,j) - m.getEntry(i)) ;
            v[i] = sum/ (samples-1);
        }
        return new ArrayRealVector(v);
    }
    //Returns the unbiased covariance matrix of the data 
    public RealMatrix covariance()
    {
      RealVector mean = mean();
      double[][] aData = data.getData();
      double[][] aCov = new double[dim][dim];
      for(int i = 0;i < dim;i++)
      {
        for(int j = i;j < dim;j++)
        {
          double sCov = 0;
          for(int k = 0;k < samples;k++)
          {
            sCov += (aData[i][k] - mean.getEntry(i)) * (aData[j][k] - mean.getEntry(j));
          }
          sCov /= (samples-1);
          aCov[i][j] = sCov;
          aCov[j][i] = sCov;
        }
      }
//        for(int i = 0 ; i < dim; i++) {
//            for (int j = 0; j < dim; j++) {
//                System.out.printf("%.2f ", aCov[i][j]);
//            }
//            System.out.println();
//        }
      return new Array2DRowRealMatrix(aCov);
    }

}

